/*

懒执行的effect
获取computed.value的时候再执行

*/

let data = {
    foo: 1,
    bar: 2
}
const weakMap = new WeakMap()
let activeEffect
let effectStack = []

data = new Proxy(data, {
    get(target, prop) {
        track(target, prop)
        return Reflect.get(...arguments)
    },
    set(target, prop, val) {
        Reflect.set(...arguments)
        trigger(target, prop)
    }
})

function track(target, prop) {
    if (!activeEffect) return
    if (!weakMap.has(target)) weakMap.set(target, new Map())
    const map = weakMap.get(target)
    if (!map.has(prop)) map.set(prop, new Set())
    const set = map.get(prop)
    set.add(activeEffect)
    activeEffect.deps.push(set)
}

function trigger(target, prop) {
    const set = weakMap.get(target)?.get(prop)
    if (!set) return
    const newSet = new Set()
    set.forEach(fn => activeEffect != fn && newSet.add(fn));
    newSet.forEach(fn => {
        if (fn.options?.scheduler) {
            fn.options.scheduler(fn)
        } else {
            fn()
        }
    })
}

function effect(fn, options) {
    const wrapper = function () {
        wrapper.deps.forEach(set => {
            set.delete(activeEffect)
        })
        effectStack.push(wrapper)
        activeEffect = effectStack.at(-1)
        const res = fn()
        effectStack.pop()
        activeEffect = effectStack.at(-1)
        return res
    }
    wrapper.deps = []
    wrapper.options = options
    if (options.lazy) {
        return wrapper
    }
    wrapper()
}

function fn() {
    console.log(data.foo);
}

let queue = new Set()
let isBusy = false

function flush() {
    if (isBusy) return
    isBusy = true
    Promise.resolve().then(() => {
        queue.forEach(fn => fn())
    }).finally(() => {
        isBusy = false
    })
}


function computed(fn) {
    const wrapper = effect(fn, options = {
        lazy: true
    })
    let obj = {
        get value() {
            return wrapper()
        }
    }
    return obj
    // return wrapper()
}

function watch(data, cb) {
    effect(() => data.foo, {
        scheduler: () => cb()
    })
}

watch(
    data,
    () => {
        console.log(data.foo);
    })

data.foo++


